#!/usr/bin/env bash
set -e
if [ "${PDNS_DEBUG}" = "YES" ]; then
  set -x
fi

if [ -z "$PDNS_BUILD_PATH" ]; then
  # PDNS_BUILD_PATH is unset or empty. Assume an autotools build.
  PDNS_BUILD_PATH=.

  export PDNS=${PDNS:-${PWD}/../pdns/pdns_server}
  export PDNS2=${PDNS2:-${PWD}/../pdns/pdns_server}
  export PDNSRECURSOR=${PDNSRECURSOR:-${PWD}/../pdns/recursordist/pdns_recursor}
  export RECCONTROL=${RECCONTROL:-${PWD}/../pdns/recursordist/rec_control}
  export SDIG=${SDIG:-${PWD}/../pdns/sdig}
  export NOTIFY=${NOTIFY:-${PWD}/../pdns/pdns_notify}
  export NSEC3DIG=${NSEC3DIG:-${PWD}/../pdns/nsec3dig}
  export SAXFR=${SAXFR:-${PWD}/../pdns/saxfr}
  export ZONE2SQL=${ZONE2SQL:-${PWD}/../pdns/zone2sql}
  export ZONE2LDAP=${ZONE2LDAP:-${PWD}/../pdns/zone2ldap}
  export ZONE2JSON=${ZONE2JSON:-${PWD}/../pdns/zone2json}
  export PDNSUTIL=${PDNSUTIL:-${PWD}/../pdns/pdnsutil}
  export PDNSCONTROL=${PDNSCONTROL:-${PWD}/../pdns/pdns_control}
else
  export PDNS=${PDNS:-$PDNS_BUILD_PATH/pdns-auth}
  export PDNS2=${PDNS2:-$PDNS_BUILD_PATH/pdns-auth}
  export PDNSRECURSOR=${PDNSRECURSOR:-$PDNS_BUILD_PATH/pdns/recursordist/pdns_recursor}
  export RECCONTROL=${RECCONTROL:-$PDNS_BUILD_PATH/pdns/recursordist/rec_control}
  export SDIG=${SDIG:-$PDNS_BUILD_PATH/sdig}
  export NOTIFY=${NOTIFY:-$PDNS_BUILD_PATH/pdns-auth-notify}
  export NSEC3DIG=${NSEC3DIG:-$PDNS_BUILD_PATH/nsec3dig}
  export SAXFR=${SAXFR:-$PDNS_BUILD_PATH/saxfr}
  export ZONE2SQL=${ZONE2SQL:-$PDNS_BUILD_PATH/pdns-zone2sql}
  export ZONE2JSON=${ZONE2JSON:-$PDNS_BUILD_PATH/pdns-zone2json}
  export ZONE2LDAP=${ZONE2LDAP:-$PDNS_BUILD_PATH/pdns-zone2ldap}
  export PDNSUTIL=${PDNSUTIL:-$PDNS_BUILD_PATH/pdns-auth-util}
  export PDNSCONTROL=${PDNSCONTROL:-$PDNS_BUILD_PATH/pdns-auth-control}
fi

export RESOLVERIP=${RESOLVERIP:-8.8.8.8}
export FIX_TESTS=${FIX_TESTS:-NO}

ALGORITHM=${ALGORITHM:="hmac-md5"}
KEY=${KEY:="kp4/24gyYsEzbuTVJRUMoqGFmN3LYgVDzJ/3oRSP7ys="}

MAKE=${MAKE:-make}

export ALGORITHM
export KEY

_show_help=0
for arg; do
    case "$arg" in
        (--help|help)
            _show_help=1
            ;;
    esac
done; unset -v arg
if [ "$_show_help" -eq 1 ]; then
        grep -v '^#' << '__EOF__'

Usage: ./start-test-stop <port> [<context>] [wait|nowait] [<cachettl>] [<specifictest>]

context is one of:
bind bind-dnssec bind-dnssec-nsec3 bind-dnssec-nsec3-optout bind-dnssec-nsec3-narrow
geoip geoip-nsec3-narrow
gmysql-nodnssec gmysql gmysql-nsec3 gmysql-nsec3-optout gmysql-nsec3-narrow gmysql_sp
godbc_mssql-nodnssec godbc_mssql godbc_mssql-nsec3 godbc_mssql-nsec3-optout godbc_mssql-nsec3-narrow
godbc_sqlite3-nodnssec godbc_sqlite3 godbc_sqlite3-nsec3 godbc_sqlite3-nsec3-optout godbc_sqlite3-narrow
gpgsql-nodnssec gpgsql gpgsql-nsec3 gpgsql-nsec3-optout gpgsql-nsec3-narrow gpgsql_sp
gsqlite3-nodnssec gsqlite3 gsqlite3-nsec3 gsqlite3-nsec3-optout gsqlite3-nsec3-narrow
lmdb-nodnssec lmdb
remotebackend-pipe remotebackend-unix remotebackend-http remotebackend-zeromq
remotebackend-pipe-dnssec remotebackend-unix-dnssec remotebackend-http-dnssec remotebackend-zeromq-dnssec
#remotebackend-pipe-nsec3 remotebackend-unix-nsec3 remotebackend-http-nsec3
#remotebackend-pipe-nsec3-narrow remotebackend-unix-nsec3-narrow remotebackend-http-nsec3-narrow
tinydns
ldap-tree ldap-simple ldap-strict
lua2 lua2-dnssec lua2-nsec3 lua2-nsec3-narrow
#ext-nsd ext-nsd-nsec ext-nsd-nsec3 ext-bind ext-bind-nsec ext-bind-nsec3

* Add -presigned to any ext-nsd, ext-bind, bind, gmysql or gsqlite3 test (except narrow)
  to test presigned operation.

* Add -both to any bind or gmysql test (except narrow) to
  test normal and presigned operation.

* Add 'wait' (literally) after the context to not kill
  pdns_server immediately after testing. 'nowait' will kill it.

* A cachettl can be supplied if you want to run tests with a
  ttl setting set. The default cachettl is 0.

* Specifictest can be used to run only one single test.
__EOF__
        exit
fi
unset -v _show_help

trap "kill_process 2" EXIT INT TERM

source ../regression-tests/common

bindwait ()
{
        check_process
        configname=$1
        domcount=$(grep -c ^zone named.conf)
        if [ ! -x $PDNSCONTROL ]
        then
                echo "No pdns_control found"
                exit
        fi
        loopcount=0

        while [ $loopcount -lt 20 ]
        do
                sleep 5
                done=$( ($PDNSCONTROL --config-name=$configname --socket-dir=. --no-config bind-domain-status || true) | grep -c 'parsed into memory' || true )
                if [ $done = $domcount ]
                then
                        return
                fi
                let loopcount=loopcount+1
        done

        if [ $done != $domcount ]
        then
                echo "Domain parsing failed" >> failed_tests
        fi
}

securezone ()
{
        local zone=$1
        local configname=$2

        if [ -n "$configname" ]
        then
                configname="--config-name=$configname"
        fi
        if [ "${zone: 0:16}" = "secure-delegated" ]
        then
                $PDNSUTIL --config-dir=. $configname import-zone-key $zone $zone.private ksk 2>&1
                $PDNSUTIL --config-dir=. $configname add-zone-key $zone rsasha256 1024 zsk active 2>&1
                $PDNSUTIL --config-dir=. $configname rectify-zone $zone 2>&1
                $PDNSUTIL --config-dir=. $configname set-publish-cds $zone 2>&1
                $PDNSUTIL --config-dir=. $configname set-publish-cdnskey $zone 2>&1
        else
                # check if PKCS#11 should be used
                if [ "$pkcs11" -eq 1 ]; then
                        if [ "$slot" == "" ]; then
                                slot=0
                        else
                                slot=$((slot+1))
                        fi
                        label=pdnstest-${EPOCHSECONDS}-${slot}
                        softhsm2-util --delete-token --label $label 2> /dev/null || true
                        softhsm2-util --init-token --label $label --free --pin 1234 --so-pin 1234
                        kid=`$PDNSUTIL --config-dir=. $configname hsm assign $zone ecdsa256 ksk softhsm2 $label 1234 $label 2>&1 | grep softhsm | awk '{ print $NF }'`
                        $PDNSUTIL --config-dir=. $configname hsm create-key $zone $kid
                        $PDNSUTIL --config-dir=. $configname rectify-zone $zone 2>&1
                else
                        $PDNSUTIL --config-dir=. $configname secure-zone $zone 2>&1
                fi
                if [ "${zone: 0:20}" = "cdnskey-cds-test.com" ]; then
                        $PDNSUTIL --config-dir=. $configname set-publish-cds $zone 2>&1
                        $PDNSUTIL --config-dir=. $configname set-publish-cdnskey $zone 2>&1
                fi
                if [ "$zone" = "dnssec-parent.com" ]; then
                        $PDNSUTIL --config-dir=. $configname set-publish-cds $zone 0 2>&1
                        $PDNSUTIL --config-dir=. $configname set-publish-cdnskey $zone delete 2>&1
                fi
        fi
}

kill_process ()
{
        set +e
        trap - EXIT INT TERM

        if [ $1 -gt 1 ]
        then
                echo "exitvalue$1" >> failed_tests
                ./toxml
                ./totar
        fi

        pids=$(cat pdns*.pid)

        if [ -n "$pids" ]
        then
                kill $pids
                # make sure they die.
                loopcount=0
                done=0
                while [ $loopcount -lt 10 ] && [ $done -eq 0 ]
                do
                        done=1
                        for pid in $pids
                        do
                                kill -0 $pid > /dev/null 2>&1
                                if [ $? -eq 0 ];
                                then
                                        done=0
                                fi
                        done
                        let loopcount=loopcount+1
                        sleep 1
                done

                kill -9 $pids
        fi

        rm pdns*.pid
        exit $1
}

if [ ! -x $PDNS ]
 then
        echo "$PDNS is not executable binary"
        exit
fi

if [ ! -x $PDNS2 ]
then
        echo "$PDNS2 is not executable binary"
        exit
fi

address="${PDNS_LISTEN_ADDR:-127.0.0.1}"
port=$1
[ -z "$port" ] && port=5300
context=$2
[ -z "$context" ] && context=bind-dnssec
wait=$3
[ -z "$wait" ] && wait=nowait
cachettl=$4
[ -z "$cachettl" ] && cachettl=0
spectest=$5

testsdir=./tests

for prog in $SDIG $SAXFR $NOTIFY $NSEC3DIG; do
  if [ ! -x "$prog" ]; then
    echo "Error: cannot find $prog, please build it."
    exit 1
  fi
done

# Copy original zones because the test might modify them (well only the dyndns stuff, but let's make this work for others as well)
for zone in $(grep 'zone ' named.conf  | cut -f2 -d\")
do
        if [ -f zones/$zone.orig ]
        then
                cp -f zones/$zone.orig zones/$zone
        fi
done

rm -f pdns*.pid
rm -f *_tests
rm -f pdns-*.conf

presigned=no
both=no

if [[ "$context" =~ .+-presigned.* ]]
then
        presigned=yes
        port=$((port-100))
        eval "$(echo "$context" | sed -r 's/(.+)(-presigned)(-(.*))?/context=\1 presignedcontext=\4/')"
        if [ -z "$presignedcontext" ]
        then
                presignedcontext=$context
        fi
fi

if [ "${context: -5}" = "-both" ]
then
        both=yes
        port=$((port-100))
        context=${context%-both}
        presignedcontext=$context
fi

optout=0
pkcs11=0

if [ "${context: -13}" = "-nsec3-optout" ]
then
        optout=1
fi

if [ "${context: -7}" = "-pkcs11" ]
then
        pkcs11=1
        context=${context:0:-7}
fi

# check for lua
if $PDNS --version 2>&1 | grep Features: | grep -q "lua"
then
  lua_prequery="--lua-prequery-script=./check_stest_source"
  skiplua=0
else
  lua_prequery=""
  skiplua=1
fi

source backends/common

start_master

if [ "$skiplua" == "1" ]; then
        skipreasons="$skipreasons nolua"
fi

check_process

dotests () {
        nameserver=127.0.0.1 ./runtests $spectest
        ./toxml
        ./totar

        cat ./trustedkeys

        if [ -s "./failed_tests" ]
        then
                for t in `cat failed_tests`
                do
                        echo -e "\n\n$t"
                        cat ${testsdir}/$t/diff
                done
                if [ "${!1}" -eq 0 ]
                then
                        eval "$1=1"
                fi
        fi
}

## TODO: give sdig a timeout

RETVAL=0

export address
export port
export context
export extracontexts
export skipreasons
export backend
export testsdir
export optout

sleep 2

if [ $presigned = no ] || [ $both = yes ]
then
        dotests RETVAL
fi

if [ $presigned = yes ] || [ $both = yes ]
then
        start_slave

        export port
        export context
        export skipreasons
        export backend

        dotests RETVAL
fi

if [ "$wait" = "wait" ]
then
        echo tests done! push enter to terminate instance
        read l
fi

trap "kill_process $RETVAL" EXIT
